/********************************************************************************
 * Copyright (c)2016-2020, ShenZhen WanJiaAn Technology CO.,LTD.
 * All Rights Reserved.
 *
 * File Name     : media_audio.c
 * Author        : joki.zhu
 * Date          : 2019-10-11
 *
 * Record        :
 * 1.Date        : 2019-10-11
 *   Author      : joki.zhu
 *   Modification: Created file
 ********************************************************************************/
#include "sample_comm.h"
#include "aacdec.h"
#include "aacenc.h"
#include "audio_aac_adp.h"
#include "adpt_acap_acodec.h"
#include "app_common.h"

#ifdef YD_PROTOCOL
#define SAMPLE_AUDIO_PTNUMPERFRM   80
#else
#define SAMPLE_AUDIO_PTNUMPERFRM   480
#endif

#ifdef AUDIO_AEC_MODE
//静态注册VQE算法库
HI_S32 AUDIO_RegisterVQEModule(HI_VOID)
{
#ifdef MINI_APP
    return HI_SUCCESS;
#endif /* MINI_APP */

    HI_S32 s32Ret = HI_SUCCESS;
    AUDIO_VQE_REGISTER_S stVqeRegCfg = {0};

    //Resample
    stVqeRegCfg.stResModCfg.pHandle = HI_VQE_RESAMPLE_GetHandle();

    //RecordVQE
    stVqeRegCfg.stRecordModCfg.pHandle = HI_VQE_RECORD_GetHandle();

    //TalkVQE
    stVqeRegCfg.stHpfModCfg.pHandle = HI_VQE_HPF_GetHandle();
    stVqeRegCfg.stAecModCfg.pHandle = HI_VQE_AEC_GetHandle();
    stVqeRegCfg.stAgcModCfg.pHandle = HI_VQE_AGC_GetHandle();
    stVqeRegCfg.stAnrModCfg.pHandle = HI_VQE_ANR_GetHandle();
    stVqeRegCfg.stEqModCfg.pHandle = HI_VQE_EQ_GetHandle();

    s32Ret = HI_MPI_AUDIO_RegisterVQEModule(&stVqeRegCfg);
    if (s32Ret != HI_SUCCESS)
    {
        LOGE("%s: register vqe module fail with s32Ret = %d!\n", __FUNCTION__, s32Ret);
        return HI_FAILURE;
    }

    LOGD("SAMPLE_AUDIO_RegisterVQEModule OK!\n");
    
    return HI_SUCCESS;
}
#endif /* AUDIO_AEC_MODE */


HI_S32 MW_Media_InitAudioAi(HI_HANDLE hACapHdl, HI_HANDLE hAEncHdl)
{    
    HI_S32 s32Ret = HI_SUCCESS;
    AUDIO_DEV AiDev = hACapHdl;
    AENC_CHN AeChn = hAEncHdl;
    AENC_CHN_ATTR_S stAencAttr = {0};
    AENC_ATTR_AAC_S stAACAttr = {0};
    AIO_ATTR_S stAiAttr = {0};

    #ifdef YD_PROTOCOL
    stAiAttr.enSamplerate   = AUDIO_SAMPLE_RATE_8000;
    #else
    stAiAttr.enSamplerate   = AUDIO_SAMPLE_RATE_16000;
    #endif
    stAiAttr.enBitwidth     = AUDIO_BIT_WIDTH_16;
    stAiAttr.enWorkmode     = AIO_MODE_I2S_MASTER;
    stAiAttr.enSoundmode    = AUDIO_SOUND_MODE_MONO;
    stAiAttr.u32EXFlag      = 0;
    stAiAttr.u32FrmNum      = 30;
    stAiAttr.u32PtNumPerFrm = SAMPLE_AUDIO_PTNUMPERFRM;
    stAiAttr.u32ChnCnt      = 1;
    stAiAttr.u32ClkSel      = 0;
    
    s32Ret = ADPT_ACODEC_Init(stAiAttr.enSamplerate);
    if (HI_SUCCESS != s32Ret)
    {
        LOGE("ADPT_ACODEC_Init failed %#x\n", s32Ret);
        return s32Ret;
    }

    s32Ret = HI_MPI_AI_SetPubAttr(AiDev, &stAiAttr);
    if (HI_SUCCESS != s32Ret)
    {
        LOGE("HI_MPI_AI_SetPubAttr fail,ret:%x\n", s32Ret);
        goto EXIT_ACODEC_DEINIT;
    }
    s32Ret = HI_MPI_AI_Enable(AiDev);
    if (HI_SUCCESS != s32Ret)
    {
        LOGE("HI_MPI_AI_Enable fail,ret:%x\n", s32Ret);
        goto EXIT_ACODEC_DEINIT;
    }

    s32Ret = HI_MPI_AI_EnableChn(AiDev, hAEncHdl);
    if (HI_SUCCESS != s32Ret)
    {
        LOGE("HI_MPI_AI_EnableChn fail,ret:%x\n", s32Ret);
        goto EXIT_AI_DISABLE;
    }

#if 1
    s32Ret = ADPT_ACODEC_SetAIVol(50);
    if (HI_SUCCESS != s32Ret)
    {
        LOGE("HI_MPI_AI_Enable fail,ret:%x\n", s32Ret);
        goto EXIT_AI_DISABLE;
    }
#endif

#ifdef AUDIO_AEC_MODE
#if 1
    //AEC回声抑制
    AI_TALKVQE_CONFIG_S stAiVqeTalkAttr;
    HI_S16 s16ERLBand[6] = {4,6,36,49,50,51};
    HI_S16 s16ERL[7] = {7,10,16,10,18,18,18};
     
    memset(&stAiVqeTalkAttr, 0, sizeof(AI_TALKVQE_CONFIG_S));
    #ifdef YD_PROTOCOL
    stAiVqeTalkAttr.s32WorkSampleRate    = AUDIO_SAMPLE_RATE_8000;
    #else
    stAiVqeTalkAttr.s32WorkSampleRate    = AUDIO_SAMPLE_RATE_16000;
    #endif
    stAiVqeTalkAttr.s32FrameSample       = SAMPLE_AUDIO_PTNUMPERFRM;
    stAiVqeTalkAttr.enWorkstate          = VQE_WORKSTATE_COMMON;
    /* stAiVqeTalkAttr.stAecCfg.bUsrMode    = HI_FALSE; */
    stAiVqeTalkAttr.stAecCfg.bUsrMode    = HI_TRUE;
    stAiVqeTalkAttr.stAecCfg.s8CngMode   = 0;
    stAiVqeTalkAttr.stAecCfg.s8NearAllPassEnergy = 1; //default:1
    stAiVqeTalkAttr.stAecCfg.s8NearCleanSupEnergy = 2; //default:2
    stAiVqeTalkAttr.stAecCfg.s16DTHnlSortQTh = 16384; //default:16384
#if 1 //ok
    stAiVqeTalkAttr.stAecCfg.s16EchoBandLow = 10; //default:10
    stAiVqeTalkAttr.stAecCfg.s16EchoBandHigh = 15; //default:41
    stAiVqeTalkAttr.stAecCfg.s16EchoBandLow2 = 20; //default:47
    stAiVqeTalkAttr.stAecCfg.s16EchoBandHigh2 = 27; //default:72
#else
    stAiVqeTalkAttr.stAecCfg.s16EchoBandLow = 10; //default:10
    stAiVqeTalkAttr.stAecCfg.s16EchoBandHigh = 41; //default:41
    stAiVqeTalkAttr.stAecCfg.s16EchoBandLow2 = 47; //default:47
    stAiVqeTalkAttr.stAecCfg.s16EchoBandHigh2 = 63; //default:72
#endif
    memcpy(&stAiVqeTalkAttr.stAecCfg.s16ERLBand, &s16ERLBand, sizeof(s16ERLBand));//default
    memcpy(&stAiVqeTalkAttr.stAecCfg.s16ERL, &s16ERL, sizeof(s16ERL));//default
    stAiVqeTalkAttr.stAecCfg.s16VioceProtectFreqL = 3;   //default
    stAiVqeTalkAttr.stAecCfg.s16VioceProtectFreqL1 = 6; //default

    //AGC自动增益
    stAiVqeTalkAttr.stAgcCfg.bUsrMode    = HI_FALSE;

    //ANR语音降噪
    stAiVqeTalkAttr.stAnrCfg.bUsrMode = HI_TRUE;
    stAiVqeTalkAttr.stAnrCfg.s16NrIntensity = 25; //降噪力度配置,取值为[0, 25]
    stAiVqeTalkAttr.stAnrCfg.s16NoiseDbThr = 60;  //噪声门限配置,取值为[30,60],配置值越大,检测力度越弱,声音更平滑
    stAiVqeTalkAttr.stAnrCfg.s8SpProSwitch = 0;  //音乐检测开关,取值为[0,1]

    //HPF高通滤波
    stAiVqeTalkAttr.stHpfCfg.bUsrMode    = HI_TRUE;
    stAiVqeTalkAttr.stHpfCfg.enHpfFreq   = AUDIO_HPF_FREQ_150;

    //Vqe对应功能使能掩码开关
    //stAiVqeTalkAttr.u32OpenMask = AI_TALKVQE_MASK_AEC | AI_TALKVQE_MASK_AGC | AI_TALKVQE_MASK_ANR | AI_TALKVQE_MASK_HPF;
    stAiVqeTalkAttr.u32OpenMask = AI_TALKVQE_MASK_AEC | AI_TALKVQE_MASK_AGC | AI_TALKVQE_MASK_ANR | AI_TALKVQE_MASK_HPF;
#else
    AI_TALKVQE_CONFIG_S stAiVqeTalkAttr;
    memset(&stAiVqeTalkAttr, 0, sizeof(AI_TALKVQE_CONFIG_S));
    stAiVqeTalkAttr.s32WorkSampleRate    = AUDIO_SAMPLE_RATE_16000;
    stAiVqeTalkAttr.s32FrameSample       = SAMPLE_AUDIO_PTNUMPERFRM;
    stAiVqeTalkAttr.enWorkstate          = VQE_WORKSTATE_COMMON;
    stAiVqeTalkAttr.stAgcCfg.bUsrMode    = HI_FALSE;
    stAiVqeTalkAttr.stAecCfg.bUsrMode    = HI_FALSE;
    stAiVqeTalkAttr.stAnrCfg.bUsrMode    = HI_FALSE;
    stAiVqeTalkAttr.stHpfCfg.bUsrMode    = HI_TRUE;
    stAiVqeTalkAttr.stHpfCfg.enHpfFreq   = AUDIO_HPF_FREQ_150;

    stAiVqeTalkAttr.u32OpenMask = AI_TALKVQE_MASK_HPF | AI_TALKVQE_MASK_ANR;

#endif
    s32Ret = HI_MPI_AI_SetTalkVqeAttr(AiDev, 0, 0, 0, (AI_TALKVQE_CONFIG_S *)&stAiVqeTalkAttr);
    if (HI_SUCCESS != s32Ret)
    {
        LOGE("HI_MPI_AI_SetTalkVqeAttr(%d,%d) failed with %#x\n", AiDev, 0, s32Ret);
        goto EXIT_AI_DISABLE;
    }
    
    s32Ret = HI_MPI_AI_EnableVqe(AiDev, 0);
    if (s32Ret)
    {
        LOGE("HI_MPI_AI_EnableVqe(%d,%d) failed with %#x\n", AiDev, 0, s32Ret);
        goto EXIT_AI_DISABLE;
    }
#endif /* AUDIO_AEC_MODE */

#ifdef YD_PROTOCOL
    AENC_ATTR_G711_S stAencG711;
    stAencAttr.enType = PT_G711A;
    stAencAttr.u32BufSize = 30;
    stAencAttr.u32PtNumPerFrm = SAMPLE_AUDIO_PTNUMPERFRM;
    stAencAttr.pValue = &stAencG711;
#else
    s32Ret = HI_MPI_AENC_AacInit();
    if (HI_SUCCESS != s32Ret)
    {
        LOGE("HI_MPI_AENC_AacInit fail,ret:%x\n", s32Ret);
        goto EXIT_AI_DISABLE;
    }

    stAencAttr.enType = PT_AAC;
    stAACAttr.enAACType = AAC_TYPE_AACLC;
    stAACAttr.enBitRate = AAC_BPS_48K;
    stAACAttr.enBitWidth = AUDIO_BIT_WIDTH_16;
    stAACAttr.enSmpRate = AUDIO_SAMPLE_RATE_16000;
    stAACAttr.enSoundMode = AUDIO_SOUND_MODE_MONO;
    stAACAttr.enTransType = AAC_TRANS_TYPE_ADTS;
    stAACAttr.s16BandWidth = 0;
    stAencAttr.pValue = &stAACAttr;
    stAencAttr.u32BufSize = 30;
    stAencAttr.u32PtNumPerFrm = 1024;
#endif /* YD_PROTOCOL */
    s32Ret = HI_MPI_AENC_CreateChn(AeChn, &stAencAttr);
    if (HI_SUCCESS != s32Ret)
    {
        LOGE("HI_MPI_AENC_CreateChn fail,ret:%x\n", s32Ret);
        goto EXIT_AI_DISABLE;
    }

    return HI_SUCCESS;

EXIT_AI_DISABLE:
    HI_MPI_AI_Disable(AiDev);
EXIT_ACODEC_DEINIT:
    ADPT_ACODEC_DeInit();

    return s32Ret;
}

HI_VOID MW_Media_DeinitAudioAi(HI_HANDLE hACapHdl, HI_HANDLE hAEncHdl)
{
    AENC_CHN AeChn = hAEncHdl;
    AUDIO_DEV AiDev = hACapHdl;
    HI_MPI_AENC_DestroyChn(AeChn);
    HI_MPI_AI_Disable(AiDev);
    ADPT_ACODEC_DeInit();
}

HI_S32 MW_Media_InitAudioAo(HI_HANDLE hAoHdl)
{
    HI_S32 s32Ret = HI_SUCCESS;
    AUDIO_DEV AoDev = hAoHdl;
    AO_CHN AoChn = 0;
    AIO_ATTR_S stAoAttr = {0};

    #ifdef YD_PROTOCOL
    stAoAttr.enSamplerate   = AUDIO_SAMPLE_RATE_8000;
    #else
    stAoAttr.enSamplerate   = AUDIO_SAMPLE_RATE_16000;
    #endif
    stAoAttr.enBitwidth     = AUDIO_BIT_WIDTH_16;
    stAoAttr.enWorkmode     = AIO_MODE_I2S_MASTER;
    stAoAttr.enSoundmode    = AUDIO_SOUND_MODE_MONO;
    stAoAttr.u32EXFlag      = 0;
    stAoAttr.u32FrmNum      = 30;
    stAoAttr.u32PtNumPerFrm = SAMPLE_AUDIO_PTNUMPERFRM;
    stAoAttr.u32ChnCnt      = 1;
    stAoAttr.u32ClkSel      = 0;
    stAoAttr.enI2sType      = AIO_I2STYPE_INNERCODEC;
    s32Ret = ADPT_ACODEC_Init(stAoAttr.enSamplerate);
    if (HI_SUCCESS != s32Ret)
    {
        LOGE("ADPT_ACODEC_Init failed %#x\n", s32Ret);
        return s32Ret;
    }

    s32Ret = HI_MPI_AO_SetPubAttr(AoDev, &stAoAttr);
    if (HI_SUCCESS != s32Ret)
    {
        LOGE("HI_MPI_AO_SetPubAttr fail,ret:%x\n", s32Ret);
        goto EXIT_ACODEC_DEINIT;
    }
    
    s32Ret = HI_MPI_AO_Enable(AoDev);
    if (HI_SUCCESS != s32Ret)
    {
        LOGE("HI_MPI_AO_Enable fail,ret:%x\n", s32Ret);
        goto EXIT_ACODEC_DEINIT;
    }

    s32Ret = HI_MPI_AO_EnableChn(AoDev, AoChn);
    if (HI_SUCCESS != s32Ret)
    {
        LOGE("HI_MPI_AO_EnableChn fail,ret:%x\n", s32Ret);
        goto EXIT_AO_DISABLE;
    }

    s32Ret =  ADPT_ACODEC_SetAOVol(100);
    if (HI_SUCCESS != s32Ret)
    {
        LOGE("ADPT_ACODEC_SetAOVol fail,ret:%x\n", s32Ret);
        goto EXIT_AO_DISABLE;
    }

#ifdef AUDIO_AEC_MODE
    AO_VQE_CONFIG_S stAoVqeAttr;
    
    memset(&stAoVqeAttr, 0, sizeof(AO_VQE_CONFIG_S));

    #ifdef YD_PROTOCOL
    stAoVqeAttr.s32WorkSampleRate    = AUDIO_SAMPLE_RATE_8000;
    #else
    stAoVqeAttr.s32WorkSampleRate    = AUDIO_SAMPLE_RATE_16000;
    #endif
    stAoVqeAttr.s32FrameSample       = SAMPLE_AUDIO_PTNUMPERFRM;
    stAoVqeAttr.enWorkstate          = VQE_WORKSTATE_COMMON;

    //AGC自动增益
    stAoVqeAttr.stAgcCfg.bUsrMode    = HI_FALSE;

    //Anr降噪
#if 1
    stAoVqeAttr.stAnrCfg.bUsrMode = HI_TRUE;
    stAoVqeAttr.stAnrCfg.s16NrIntensity = 25;//降噪力度配置，取值为[0, 25]
    stAoVqeAttr.stAnrCfg.s16NoiseDbThr = 60;//噪声门限配置，取值为[30,60]，配置值越大，检测力度越弱，声音更平滑
    stAoVqeAttr.stAnrCfg.s8SpProSwitch = 0;//音乐检测开关，取值为[0,1]
#endif

    //HPF高通滤波
    stAoVqeAttr.stHpfCfg.bUsrMode    = HI_TRUE;
    stAoVqeAttr.stHpfCfg.enHpfFreq   = AUDIO_HPF_FREQ_150;

    stAoVqeAttr.u32OpenMask = AO_VQE_MASK_EQ | AO_VQE_MASK_AGC | AO_VQE_MASK_ANR | AO_VQE_MASK_HPF;
//    stAoVqeAttr.u32OpenMask = AO_VQE_MASK_EQ | AO_VQE_MASK_ANR | AO_VQE_MASK_HPF;
//    stAoVqeAttr.u32OpenMask = AO_VQE_MASK_ANR | AO_VQE_MASK_HPF;
    //stAoVqeAttr.u32OpenMask = AO_VQE_MASK_AGC;
    
    s32Ret = HI_MPI_AO_SetVqeAttr(AoDev, AoChn, &stAoVqeAttr);
    if(HI_SUCCESS != s32Ret)
    {
        LOGE("HI_MPI_AO_SetVqeAttr(%d) failed with %#x!\n", AoChn, s32Ret);
        goto EXIT_AO_DISABLE;
    }


    s32Ret = HI_MPI_AO_EnableVqe(AoDev, AoChn);
    if (s32Ret)
    {
        printf("HI_MPI_AO_EnableVqe(%d,%d) failed with %#x\n", AoChn, AoChn, s32Ret);
        goto EXIT_AO_DISABLE;
    }
#endif /* AUDIO_AEC_MODE */

    return HI_SUCCESS;

EXIT_AO_DISABLE:
    HI_MPI_AO_Disable(AoDev);
EXIT_ACODEC_DEINIT:
    ADPT_ACODEC_DeInit();

    return s32Ret;
}

HI_S32 MW_Media_AoSendFrame(HI_HANDLE hAoHdl, HI_U8 *pu8PCMData, HI_S32 u32DataLen, HI_U32 u32TimeoutMs)
{
    HI_S32 s32Ret = HI_SUCCESS;
    AUDIO_DEV AoDev = hAoHdl;
    AO_CHN AoChn = 0;
    AIO_ATTR_S stAttr = {0};
    AUDIO_FRAME_S stAoFrame;
  
    s32Ret = HI_MPI_AO_GetPubAttr(AoDev, &stAttr);
    if (HI_SUCCESS != s32Ret) {
        LOGE("HI_MPI_AO_GetPubAttr error. ret:%x \n", s32Ret);
        return s32Ret;
    }

#if  1
    memset(&stAoFrame, 0, sizeof(stAoFrame));
    stAoFrame.enBitwidth = stAttr.enBitwidth;
    stAoFrame.enSoundmode = stAttr.enSoundmode;
    stAoFrame.u32Len = u32DataLen;
    stAoFrame.u64VirAddr[0] = pu8PCMData;
    stAoFrame.u64PhyAddr[0] = (HI_U64)(HI_UL)pu8PCMData;
    
    s32Ret = HI_MPI_AO_SendFrame(AoDev, AoChn, (const AUDIO_FRAME_S*)&stAoFrame, u32TimeoutMs);
    if (HI_SUCCESS != s32Ret) {
        LOGE("HI_MPI_AO_SendFrame error. ret:%x \n", s32Ret);
        return s32Ret;
    }
#else
    HI_U32 u32FrameLen = 0;
    HI_U32 u32FrameCnt = 0;
    
    u32FrameLen = stAttr.u32PtNumPerFrm * sizeof(HI_U16);
    memset(&stAoFrame, 0, sizeof(stAoFrame));
    stAoFrame.enBitwidth = stAttr.enBitwidth;
    stAoFrame.enSoundmode = stAttr.enSoundmode;
    stAoFrame.u32Len = u32FrameLen;
    
    while (u32FrameCnt < (u32DataLen / u32FrameLen))
    {
        stAoFrame.u32Seq++;
        stAoFrame.u64VirAddr[0] = pu8PCMData;
        stAoFrame.u64PhyAddr[0] = (HI_U64)(HI_UL)pu8PCMData;

        if (AUDIO_SOUND_MODE_STEREO == stAoFrame.enSoundmode)
        {
            stAoFrame.u64VirAddr[1] = pu8PCMData;
            stAoFrame.u64PhyAddr[1] = (HI_U64)(HI_UL)pu8PCMData;
        }

        s32Ret = HI_MPI_AO_SendFrame(AoDev, AoChn, (const AUDIO_FRAME_S*)&stAoFrame, 50);
        if (HI_SUCCESS != s32Ret)
        {
            printf("HI_MPI_AO_SendFrame error. ret:%x \n", s32Ret);
            if (HI_ERR_AO_NOT_ENABLED == s32Ret) {
                break;
            }
            HI_usleep(10 * 1000);
            continue;
        }

        u32FrameCnt++;
        pu8PCMData += u32FrameLen;
        HI_usleep(10 * 1000);
    }
#endif /* #if 1 */

    return s32Ret;
}


HI_VOID MW_Media_DeinitAudioAo(HI_HANDLE hAoHdl)
{
    AUDIO_DEV AoDev = hAoHdl;
    
    HI_MPI_AO_Disable(AoDev);
    ADPT_ACODEC_DeInit();
}

